﻿using UnityEngine;
using UnityEngine.UI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Jinndev.Json;
using System.Text;
using Jinndev.UI;

namespace Jinndev {

    public static class MapUtil {

        /// <summary>
        /// Texture缓存，key为文件绝对路径
        /// </summary>
        private static Dictionary<string, Texture2D> TextureCache = new Dictionary<string, Texture2D>();

        public static SortedDictionary<string, TileConfig> tileConfigs = new SortedDictionary<string, TileConfig>();

        /// <summary>
        /// 得到图片的绝对路径
        /// </summary>
        /// <param name="relativeFile">文件名</param>
        public static string GetTextureFullPath(string relativeFile) {
            return Path.Combine(Setting.Instance.mapTextureRootDir, relativeFile);
        }

        /// <summary>
        /// 加载指定路径的图片
        /// </summary>
        public static Texture2D LoadTexture(string relativeFile) {
            if (string.IsNullOrEmpty(relativeFile)) {
                return null;
            }

            string filePath = GetTextureFullPath(relativeFile);

            if (TextureCache.TryGetValue(filePath, out Texture2D texture)) {
                return texture;
            }
            if (File.Exists(filePath)) {
                var bytes = File.ReadAllBytes(filePath);
                texture = new Texture2D(0, 0);
                texture.LoadImage(bytes);
                texture.Apply();

                TextureCache.Add(filePath, texture);
                return texture;
            }
            Debug.LogError("文件不存在: " + filePath);
            NotificationUI.Create("文件不存在: " + filePath, LogType.Error);
            return null;
        }

        /// <summary>
        /// 加载合适的图片
        /// </summary>
        public static Texture2D LoadTexture(TileConfig config) {
            string file = null;
            if (!string.IsNullOrEmpty(config.lf)) {
                file = config.lf;
            }
            else if (!string.IsNullOrEmpty(config.rf)) {
                file = config.rf;
            }
            else if (!string.IsNullOrEmpty(config.lb)) {
                file = config.lb;
            }
            else if (!string.IsNullOrEmpty(config.rb)) {
                file = config.rb;
            }
            if (file != null) {
                return LoadTexture(file);
            }
            Debug.LogError("瓦片未配置图片: " + config.id);
            NotificationUI.Create("瓦片未配置图片: " + config.id, LogType.Error);
            return null;
        }

        public static string TileConfigFile => Path.Combine(Setting.Instance.mapExportRootDir, TileConfig.NAME + ".json");

        public static void LoadTileConfig() {
            if (File.Exists(TileConfigFile)) {
                string text = File.ReadAllText(TileConfigFile, Encoding.UTF8);
                tileConfigs = JsonUtil.Deserialize<SortedDictionary<string, TileConfig>>(text);
            }
        }

        public static void SaveTileConfig(List<TileConfig> configs) {
            tileConfigs.Clear();
            foreach (var config in configs) {
                tileConfigs.Add(config.id, config);
            }
            SaveTileConfig();
        }

        public static void SaveTileConfig() {
            foreach (var data in tileConfigs.Values) {
                if (data.lf != null) {
                    data.lf = data.lf.Replace("\\", "/");
                }
                if (data.lb != null) {
                    data.lb = data.lb.Replace("\\", "/");
                }
                if (data.rf != null) {
                    data.rf = data.rf.Replace("\\", "/");
                }
                if (data.rb != null) {
                    data.rb = data.rb.Replace("\\", "/");
                }
            }
            string text = JsonUtil.Serialize(tileConfigs);
            File.WriteAllText(TileConfigFile, text, Encoding.UTF8);
        }

        /// <summary>
        /// 根据过滤条件，重载瓦片配置列表
        /// </summary>
        /// <param name="outList">用于输出结果的list</param>
        /// <param name="filterText">过滤条件</param>
        public static void ReloadTileConfigList(List<TileConfig> outList, string filterText) {
            outList.Clear();

            if (string.IsNullOrWhiteSpace(filterText)) {
                outList.AddRange(tileConfigs.Values);
            }
            else {
                foreach (TileConfig config in tileConfigs.Values) {
                    if (config.id.Contains(filterText)) {
                        outList.Add(config);
                    }
                    else if (config.id.ToString().Contains(filterText)) {
                        outList.Add(config);
                    }
                    else if (config.lf != null && config.lf.Contains(filterText)) {
                        outList.Add(config);
                    }
                    else if (config.rf != null && config.rf.Contains(filterText)) {
                        outList.Add(config);
                    }
                    else if (config.lb != null && config.lb.Contains(filterText)) {
                        outList.Add(config);
                    }
                    else if (config.rb != null && config.rb.Contains(filterText)) {
                        outList.Add(config);
                    }
                }
            }
        }

        /// <summary>
        /// 修复丢失的材质
        /// </summary>
        public static void FixLostTexturePath(List<TileConfig> list, List<string> textureList) {
            Dictionary<string, string> textureDict = new Dictionary<string, string>();
            foreach (string texture in textureList) {
                string name = Path.GetFileName(texture);
                if (!textureDict.ContainsKey(name)) {
                    textureDict.Add(name, texture);
                }
                else {
                    Debug.Log("同名图片，无法用于矫正数据: " + name);
                }
            }

            int fixCount = 0;
            foreach (TileConfig config in list) {
                FixLostTexturePath(textureDict, config.lf, out config.lf, ref fixCount);
                FixLostTexturePath(textureDict, config.rf, out config.rf, ref fixCount);
                FixLostTexturePath(textureDict, config.lb, out config.lb, ref fixCount);
                FixLostTexturePath(textureDict, config.rb, out config.rf, ref fixCount);
            }
            if (fixCount > 0) {
                NotificationUI.Create($"修复了{fixCount}个丢失图片配置\n注意保存");
                //SaveTileConfig();
            }
        }

        private static bool FixLostTexturePath(Dictionary<string, string> textureDict, string path, out string fixPath, ref int fixCount) {
            if (string.IsNullOrWhiteSpace(path)) {
                fixPath = path;
                return false;
            }

            string filePath = GetTextureFullPath(path);
            if (!File.Exists(filePath)) {
                string name = Path.GetFileName(path);
                if (textureDict.TryGetValue(name, out fixPath)) {
                    //Debug.Log($"矫正丢失图片: {path} => {fixPath}");
                    fixCount++;
                    return true;
                }
            }

            fixPath = path;
            return false;
        }

        /// <summary>
        /// 得到可用的瓦片ID
        /// </summary>
        /// <returns></returns>
        public static string NewTileID() {
            string id = "NewTile";
            string newId = CheckSameTileId(id);
            while (newId != id) {
                id = newId;
                newId = CheckSameTileId(id);
            }
            return newId;
        }

        public static string CheckSameTileId(string id) {
            foreach (var key in tileConfigs.Keys) {
                if (key == id) {
                    if (id.EndsWith(")") && id.Contains("(")) {
                        string num = id.Substring(id.LastIndexOf("(") + 1);
                        id = id.Substring(0, id.LastIndexOf("("));
                        num = num.Substring(0, num.Length - 1);
                        if (int.TryParse(num, out int n)) {
                            return id + $"({n + 1})";
                        }
                    }
                    return id + "(1)";
                }
            }
            return id;
        }

        public static bool ChangeId(TileConfig config, string newId) {
            if (tileConfigs.ContainsKey(newId)) {
                return false;
            }
            tileConfigs.Remove(config.id);
            config.id = newId;
            tileConfigs.Add(config.id, config);
            return true;
        }

        private static Texture[] textures = new Texture[4];
        private static float[] scales = new float[4];

        public static void SetTileTextureAndScale(RawImage image, MapObjData data) {
            if (MapEditorUI.Instance == null || !tileConfigs.TryGetValue(data.id, out TileConfig config)) {
                return;
            }

            GetTileTextureAndScale(config, textures, scales);

            Texture texture = textures[(int)data.rotation];
            Float3 scale = new Vector3(scales[(int)data.rotation], 1, 1);
            Vector3 position = MapEditorUI.Instance.GetTilePos(data.index);

            image.texture = texture;
            RectTransform tileTransform = image.transform as RectTransform;
            tileTransform.anchoredPosition = position;
            tileTransform.localScale = scale;
            tileTransform.sizeDelta = new Vector2(texture.width, texture.height);
            tileTransform.pivot = config.anchor;
            //tileTransform.pivot = new Vector2(1 - config.anchor.x, config.anchor.y);
        }

        /// <summary>
        /// 根据配置了哪些方向的图片，获得实际图片和缩放
        /// </summary>
        public static void GetTileTextureAndScale(TileConfig config, Texture[] textures, float[] scales) {
            int lf = (int)MapObjRotation.LeftFront;
            int rf = (int)MapObjRotation.RightFront;
            int lb = (int)MapObjRotation.LeftBack;
            int rb = (int)MapObjRotation.RightBack;

            textures[lf] = MapUtil.LoadTexture(config.lf);
            textures[rf] = MapUtil.LoadTexture(config.rf);
            textures[lb] = MapUtil.LoadTexture(config.lb);
            textures[rb] = MapUtil.LoadTexture(config.rb);

            if (textures[lf] != null && textures[rf] != null) {
                scales[lf] = 1;
                scales[rf] = 1;
            }
            else if (textures[lf] != null && textures[rf] == null) {
                textures[rf] = textures[lf];
                scales[lf] = 1;
                scales[rf] = -1;
            }
            else if (textures[lf] == null && textures[rf] != null) {
                textures[lf] = textures[rf];
                scales[lf] = -1;
                scales[rf] = 1;
            }

            if (textures[lb] != null && textures[rb] != null) {
                scales[lb] = 1;
                scales[rb] = 1;
            }
            else if (textures[lb] != null && textures[rb] == null) {
                textures[rb] = textures[lb];
                scales[lb] = 1;
                scales[rb] = -1;
            }
            else if (textures[lb] == null && textures[rb] != null) {
                textures[lb] = textures[rb];
                scales[lb] = -1;
                scales[rb] = 1;
            }
            else {
                textures[lb] = textures[lf];
                textures[rb] = textures[rf];
                scales[lb] = scales[lf];
                scales[rb] = scales[rf];
            }
        }

    }

}
